POJ_3276

题意

N头牛排成一列1<=N<=5000。每头牛或者向前(表示为F)或者向后(表示为B)。为了让所有牛都面向前方,农夫每次可以将K头连续的牛转向1<=K<=N,求操作的最少次数M和对应的最小K。

思路

首先满足操作次数最小,然后求最小操作长度。
第i位是否反转可以根据前[i-k+1,i-1]判断,所以维护一个sum[i-k+1,i-1],枚举操作长度k,求解。

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <map>
#include <set>
using namespace std;
#define NV 100005
#define ll long long
int n,a[5050],f[5050];
int work(int k){
memset(f,0,sizeof(f));int ret=0,sum=0;
for (int i= 1 ; i <= n - k +1 ; i++){
ret += (a[i]+sum)&1;
f[i] = (a[i]+sum)&1;
sum += f[i];
if(i - k + 1 >= 1)sum -= f[i - k + 1];
}
for(int i= n+2-k ;i <=n ; i++){
if((a[i]+sum) &1 ) return -1;
if(i - k + 1 >= 1)sum -= f[i - k + 1];
}
return ret;
}
void solve(){
int K = 1 , M = n,ret;
for(int k = 1 ; k <= n ; k++){
ret = work(k);
if(ret >= 0 && ret < M){
K = k;
M = ret;
}
}printf("%d %d\n",K,M);
}
int main(){
cin>>n;char c;
for(int i=1 ; i<=n ;i++ ){
getchar();c=getchar();
a[i] = c=='B' ? 1 : 0;
}
solve();
return 0;
}